/* Turska Framework/UI library (Turs2)
 * Copyright 2003-2010 Jetro Lauha
 * All rights reserved.
 * Web: http://iki.fi/jetro/turska/
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of EITHER:
 *   (1) The GNU Lesser General Public License as published by the Free
 *       Software Foundation; either version 2.1 of the License, or (at
 *       your option) any later version. The text of the GNU Lesser
 *       General Public License is included with this library in the
 *       file LICENSE-LGPL.txt.
 *   (2) The BSD-style license that is included with this library in
 *       the file LICENSE-BSD.txt.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
 * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
 *
 * $Id: T2VerticalStripBitmapFont.cpp 28 2012-07-28 17:03:06Z trzntaat $
 * $Revision: 28 $
 */

#include <cstring>
#include <assert.h>

#include "Turs2.h"


using namespace std;


namespace turska
{


const static C8 sDefaultFontStr[] =
    " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";


VerticalStripBitmapFont::VerticalStripBitmapFont(Graphics *graphics,
                                                 const C8 *fileName,
                                                 const C8 *fontString,
                                                 UI8 alphaTraceMinAlpha) :
    mGraphics(graphics), mAlphaTraceMinAlpha(alphaTraceMinAlpha),
    mGlyphs(0), mGlyphCount(0),
    mCharacterSpacing(1), mFontHeight(0)
{
    memset(mFileName, 0, MAX_FILENAME_LENGTH);
    memset(mGlyphMap, 0, MAX_GLYPHS * sizeof(I16));

    strncpy(mFileName, fileName, MAX_FILENAME_LENGTH - 1);

    if (fontString == 0)
        fontString = sDefaultFontStr;
    buildCharMap(fontString);
}


VerticalStripBitmapFont::~VerticalStripBitmapFont()
{
    UI32 a;
    for (a = 0; a < mGlyphCount; ++a)
        delete mGlyphs[a];
    delete[] mGlyphs;
    mGlyphs = 0;
    mGlyphCount = 0;
    mLoaded = false;
}


bool VerticalStripBitmapFont::init()
{
    return reload();
}


bool VerticalStripBitmapFont::hasCharacter(UI32 character)
{
    return mGlyphMap[(UI8)character] >= 0;
}


TREAL VerticalStripBitmapFont::getStringWidth(const C8 *string, TREAL scale, I32 substrLength)
{
    assert(mLoaded);
    if (string == 0)
        return 0;

    I32 stringWidth = 0;
    I32 g, stringLen = substrLength >= 0 ? substrLength : (I32)strlen(string);

    for (g = 0; g < stringLen && string[g]; ++g)
    {
        I32 glyphIndex = mGlyphMap[(UI8)string[g]];
        if (glyphIndex >= 0)
            stringWidth += (I32)mGlyphs[glyphIndex]->getWidth() + mCharacterSpacing;
    }

    // subtract the spacing after last character from result, scale final result
    return (stringWidth - mCharacterSpacing) * scale;
}


TREAL VerticalStripBitmapFont::drawString(TREAL x, TREAL y, const C8 *string,
                                          UI32 flags, TREAL scale,
                                          const Color &color, I32 substrLength)
{
    assert(mLoaded);
    if (string == 0)
        return 0;

    TREAL stringWidth = getStringWidth(string, scale);
    TREAL stringHeight = 0;
    I32 g, stringLen = substrLength >= 0 ? substrLength : (I32)strlen(string);

    if ((flags & IF_ALIGN_HORIZ_CENTER) > 0 ||
        (flags & IF_ALIGN_RIGHT) > 0)
    {
        // calculate row width and adjust x
        if ((flags & IF_ALIGN_HORIZ_CENTER) > 0)
            x -= stringWidth / (TREAL)2;
        else if ((flags & IF_ALIGN_RIGHT) > 0)
            x -= stringWidth;
    }
    if ((flags & IF_ALIGN_VERT_CENTER) > 0 ||
        (flags & IF_ALIGN_BOTTOM) > 0)
    {
        // calculate row height and adjust y
        stringHeight = scale * mFontHeight;
        if ((flags & IF_ALIGN_VERT_CENTER) > 0)
            y -= stringHeight / (TREAL)2;
        else if ((flags & IF_ALIGN_BOTTOM) > 0)
            y -= stringHeight;
    }

    if (scale == (TREAL)1)
    {
        x = (TREAL)((I32)x);
        y = (TREAL)((I32)y);
    }

    for (g = 0; g < stringLen && string[g]; ++g)
    {
        const UI8 ch = (UI8)string[g];
        const I32 glyphIndex = mGlyphMap[ch];
        if (glyphIndex < 0)
            continue;
        Image *glyph = (Image *)mGlyphs[glyphIndex];
        glyph->setScale(scale);
        UI32 flags = IF_COLOR | IF_ALPHA;
        if (scale != (TREAL)1)
            flags |= IF_TRANSFORM | IF_SCALE | IF_FILTER_LINEAR;
        else
        {
            // when scaling is not used, use integer coordinates - otherwise
            // nearest neighbor sampling may cause nasty looking artifacts
            x = (TREAL)((I32)x);
            y = (TREAL)((I32)y);
        }
        glyph->draw(mDrawMode, flags, x, y, color);
        x += scale * (glyph->getWidth() + mCharacterSpacing);
    }

    return stringWidth;
}


void VerticalStripBitmapFont::buildCharMap(const C8 *fontString)
{
    UI32 a, ch;

    mGlyphCount = (UI32)strlen(fontString);

    for (ch = 0; ch < MAX_GLYPHS; ++ch)
    {
        I16 mapped = -1;

        for (a = 0; a < mGlyphCount; ++a)
        {
            if (fontString[a] == (C8)ch)
            {
                mapped = a;
                break;
            }
        }

        mGlyphMap[ch] = mapped;
    }
}


} // namespace turska
